/*
 * opt_redundant_elimination.c
 *
 * Implements an optimization eliminating redundant expressions
 *
 * Edited by: Jeremy Hansen, RANDY Compton
 *
 * We remove all temporaries that are not later utilized.
 */

#include "opt_redundant_elimination.h"

// Prototype
int elim_redundant(struct tac_t **ss);

/* -----------------------------------------------------------------------
 * Applies the elimination of redundant expressions optimization.
 * -----------------------------------------------------------------------
 */
void opt_redundant_elimination(struct ir_list_t *ir_list)
{
	struct ir_list_t *temp = ir_list;
	while (temp != NULL) {
		struct ir_t *ir = temp->ir;
		// Eliminate redundant expressions within each block
		while(ir != NULL) {
			while(elim_redundant(&ir->statements));
			ir = ir->next;
		}
		temp = temp->next;
	}
}

/* -----------------------------------------------------------------------
 * Applies redundant expression elimination to a basic block
 * -----------------------------------------------------------------------
 */
int elim_redundant(struct tac_t **ss) {
	int changed = 0; // Records whether anything was eliminated
	for(; *ss != NULL; ss = &(*ss)->next) {
		struct tac_t *s;
		for(s = (*ss)->next; s != NULL; s = s->next) {
			// Is it redefined before use?
			if(strcasecmp((*ss)->v1, s->v1) == 0) { s = NULL; break; }
			// Is it used?
			if(s->v2 != NULL && strcasecmp((*ss)->v1, s->v2) == 0) break;
			if(s->v3 != NULL && strcasecmp((*ss)->v1, s->v3) == 0) break;
		}
		if(s == NULL && (*ss)->v1[0] == 't') { // Was it a redundant temporary?
			struct tac_t *temp = *ss;
			*ss = temp->next; // Unlink it from the list
			free(temp);
			changed = 1;
		}
	}
	return changed;
}
